﻿using System;
using System.Collections.Generic;
using System.Composition;
using System.Linq;
using System.Linq.Expressions;
using Ant.Interface.Data;
using NHibernate;
using NHibernate.Linq;

namespace Ant.BasicPlugIn.Data
{
    /// <summary>
    /// 储藏室控制器实现。
    /// </summary>
    [Export(typeof(IRepository<>))]
    public class Repository<T> : IRepository<T>
    {
        #region "Field"

        private readonly ISessionLocator _sessionLocator;

        #endregion "Field"

        #region "Constructor"

        public Repository(ISessionLocator sessionLocator)
        {
            _sessionLocator = sessionLocator;
        }

        #endregion "Constructor"

        #region "Property"

        protected virtual ISessionLocator SessionLocator
        {
            get { return _sessionLocator; }
        }

        protected virtual ISession Session
        {
            get { return SessionLocator.For(typeof(T)); }
        }

        #endregion "Property"

        #region Implementation of IRepository<T>

        /// <summary>
        /// 创建。
        /// </summary>
        /// <param name="entity">实体。</param>
        /// <param name="isLazy">是否延迟（是：需执行Flush方法向数据库进行提交，否：立即向数据库进行提交）。</param>
        /// <returns>新实体。</returns>
        T IRepository<T>.Create(T entity, bool isLazy)
        {
            return Create(entity, isLazy);
        }

        /// <summary>
        /// 创建或更新。
        /// </summary>
        /// <param name="entity">实体。</param>
        /// <param name="isLazy">是否延迟（是：需执行Flush方法向数据库进行提交，否：立即向数据库进行提交）。</param>
        void IRepository<T>.CreateOrUpdate(T entity, bool isLazy)
        {
            CreateOrUpdate(entity, isLazy);
        }

        /// <summary>
        /// 更新。
        /// </summary>
        /// <param name="entity">实体。</param>
        /// <param name="isLazy">是否延迟（是：需执行Flush方法向数据库进行提交，否：立即向数据库进行提交）。</param>
        void IRepository<T>.Update(T entity, bool isLazy)
        {
            Update(entity, isLazy);
        }

        /// <summary>
        /// 删除。
        /// </summary>
        /// <param name="entity">实体。</param>
        /// <param name="isLazy">是否延迟（是：需执行Flush方法向数据库进行提交，否：立即向数据库进行提交）。</param>
        void IRepository<T>.Delete(T entity, bool isLazy)
        {
            Delete(entity, isLazy);
        }

        /// <summary>
        /// 删除。
        /// </summary>
        /// <param name="id">标识。</param>
        /// <param name="isLazy">是否延迟（是：需执行Flush方法向数据库进行提交，否：立即向数据库进行提交）。</param>
        void IRepository<T>.Delete(object id, bool isLazy)
        {
            Delete(id, isLazy);
        }

        /// <summary>
        /// 获取一个实体。
        /// </summary>
        /// <typeparam name="T">实体类型。</typeparam>
        /// <param name="id">标识。</param>
        /// <returns>实体。</returns>
        T IRepository<T>.Get(object id)
        {
            return Get(id);
        }

        /// <summary>
        /// 获取一个实体。
        /// </summary>
        /// <typeparam name="T">实体类型。</typeparam>
        /// <param name="predicate">表达式。</param>
        /// <returns>实体。</returns>
        T IRepository<T>.Get(Expression<Func<T, bool>> predicate)
        {
            return Get(predicate);
        }

        IQueryable<T> IRepository<T>.Table
        {
            get { return Table; }
        }

        /// <summary>
        /// 冲刷缓冲区。
        /// </summary>
        void IRepository<T>.Flush()
        {
            Flush();
        }

        /// <summary>
        /// 计算大小。
        /// </summary>
        /// <typeparam name="T">实体类型。</typeparam>
        /// <param name="predicate">表达式。</param>
        /// <returns>大小。</returns>
        long IRepository<T>.Count(Expression<Func<T, bool>> predicate)
        {
            return Count(predicate);
        }

        /// <summary>
        /// 抓取集合。
        /// </summary>
        /// <typeparam name="T">实体类型。</typeparam>
        /// <param name="predicate">表达式。</param>
        /// <returns>集合。</returns>
        IEnumerable<T> IRepository<T>.Fetch(Expression<Func<T, bool>> predicate)
        {
            return Fetch(predicate);
        }

        /// <summary>
        /// 抓取集合。
        /// </summary>
        /// <typeparam name="T">实体类型。</typeparam>
        /// <param name="predicate">表达式。</param>
        /// <param name="order">排序。</param>
        /// <returns>集合。</returns>
        IEnumerable<T> IRepository<T>.Fetch(Expression<Func<T, bool>> predicate, Action<Orderable<T>> order)
        {
            return Fetch(predicate, order);
        }

        /// <summary>
        /// 抓取集合。
        /// </summary>
        /// <typeparam name="T">实体类型。</typeparam>
        /// <param name="predicate">表达式。</param>
        /// <param name="order">排序。</param>
        /// <param name="skip">跳过记录数（null则不跳过记录数）。</param>
        /// <param name="count">抓取的记录数（null则抓取无限大）。</param>
        /// <returns>集合。</returns>
        IEnumerable<T> IRepository<T>.Fetch(Expression<Func<T, bool>> predicate, Action<Orderable<T>> order, int? skip, int? count)
        {
            return Fetch(predicate, order, skip, count);
        }

        #endregion Implementation of IRepository<T>

        #region "Public Method"

        /// <summary>
        /// 创建。
        /// </summary>
        /// <param name="entity">实体。</param>
        /// <param name="isLazy">是否延迟（是：需执行Flush方法向数据库进行提交，否：立即向数据库进行提交）。</param>
        /// <returns>新实体。</returns>
        public virtual T Create(T entity, bool isLazy = false)
        {
            var newEntity = (T)Session.Save(entity);
            Flush(!isLazy);
            return newEntity;
        }

        /// <summary>
        /// 创建或更新。
        /// </summary>
        /// <param name="entity">实体。</param>
        /// <param name="isLazy">是否延迟（是：需执行Flush方法向数据库进行提交，否：立即向数据库进行提交）。</param>
        public virtual void CreateOrUpdate(T entity, bool isLazy = false)
        {
            Session.SaveOrUpdate(entity);
            Flush(!isLazy);
        }

        /// <summary>
        /// 更新。
        /// </summary>
        /// <param name="entity">实体。</param>
        /// <param name="isLazy">是否延迟（是：需执行Flush方法向数据库进行提交，否：立即向数据库进行提交）。</param>
        public virtual void Update(T entity, bool isLazy = false)
        {
            Session.Update(entity);
            Flush(!isLazy);
        }

        /// <summary>
        /// 删除。
        /// </summary>
        /// <param name="entity">实体。</param>
        /// <param name="isLazy">是否延迟（是：需执行Flush方法向数据库进行提交，否：立即向数据库进行提交）。</param>
        public virtual void Delete(T entity, bool isLazy = false)
        {
            Session.Delete(entity);
            Flush(!isLazy);
        }

        /// <summary>
        /// 删除。
        /// </summary>
        /// <param name="id">标识。</param>
        /// <param name="isLazy">是否延迟（是：需执行Flush方法向数据库进行提交，否：立即向数据库进行提交）。</param>
        public virtual void Delete(object id, bool isLazy = false)
        {
            Delete(Get(id), isLazy);
        }

        /// <summary>
        /// 获取一个实体。
        /// </summary>
        /// <typeparam name="T">实体类型。</typeparam>
        /// <param name="id">标识。</param>
        /// <returns>实体。</returns>
        public virtual T Get(object id)
        {
            return Session.Get<T>(id);
        }

        /// <summary>
        /// 获取一个实体。
        /// </summary>
        /// <typeparam name="T">实体类型。</typeparam>
        /// <param name="predicate">表达式。</param>
        /// <returns>实体。</returns>
        public virtual T Get(Expression<Func<T, bool>> predicate)
        {
            return Fetch(predicate).SingleOrDefault();
        }

        /// <summary>
        /// 表数据集。
        /// </summary>
        public virtual IQueryable<T> Table
        {
            get { return Session.Query<T>(); }
        }

        /// <summary>
        /// 冲刷缓冲区。
        /// </summary>
        public virtual void Flush()
        {
            Session.Flush();
        }

        /// <summary>
        /// 查询。
        /// </summary>
        /// <typeparam name="T">实体类型。</typeparam>
        /// <returns>延迟查询的集合。</returns>
        public virtual IQueryable<T> Query()
        {
            return Session.Query<T>();
        }

        /// <summary>
        /// 计算大小。
        /// </summary>
        /// <typeparam name="T">实体类型。</typeparam>
        /// <param name="predicate">表达式。</param>
        /// <returns>大小。</returns>
        public virtual long Count(Expression<Func<T, bool>> predicate)
        {
            return Fetch(predicate).LongCount();
        }

        /// <summary>
        /// 抓取集合。
        /// </summary>
        /// <typeparam name="T">实体类型。</typeparam>
        /// <param name="predicate">表达式。</param>
        /// <returns>集合。</returns>
        public virtual IQueryable<T> Fetch(Expression<Func<T, bool>> predicate)
        {
            return Query().Where(predicate);
        }

        /// <summary>
        /// 抓取集合。
        /// </summary>
        /// <typeparam name="T">实体类型。</typeparam>
        /// <param name="predicate">表达式。</param>
        /// <param name="order">排序。</param>
        /// <returns>集合。</returns>
        public virtual IQueryable<T> Fetch(Expression<Func<T, bool>> predicate, Action<Orderable<T>> order)
        {
            var orderable = new Orderable<T>(Fetch(predicate));
            order(orderable);
            return orderable.Queryable;
        }

        /// <summary>
        /// 抓取集合。
        /// </summary>
        /// <typeparam name="T">实体类型。</typeparam>
        /// <param name="predicate">表达式。</param>
        /// <param name="order">排序。</param>
        /// <param name="skip">跳过记录数（null则不跳过记录数）。</param>
        /// <param name="count">抓取的记录数（null则抓取无限大）。</param>
        /// <returns>集合。</returns>
        public virtual IQueryable<T> Fetch(Expression<Func<T, bool>> predicate, Action<Orderable<T>> order, int? skip, int? count)
        {
            var list = Fetch(predicate, order);
            if (skip.HasValue && skip.Value > 0)
            {
                list = list.Skip(skip.Value);
            }
            if (count.HasValue && count.Value > 0)
            {
                list = list.Take(count.Value);
            }
            return list;
        }

        #endregion "Public Method"

        #region "Private Method"

        private void Flush(bool isFlush)
        {
            if (isFlush)
                Flush();
        }

        #endregion "Private Method"
    }
}